/*
 * Widget for displaying a quiz
 */

#ifndef QUIZWIDGET_H
#define QUIZWIDGET_H

#include <QWidget> // must include because inheriting
#include <QList>
#include <QSize>
#include <list>
#include <QMap>
#include <QLinkedList>

#include "includes/phrase.h"

class QAbstractButton;
class QPushButton;
class QSpacerItem;

/**
 * Quiz widget which displays several options from which
 * the user must choose.
 *
 * The question which the quiz is testing is set with
 * setQuestion(), which takes a QList of Phrase's and
 * the answer Phrase which must be a member of the former.
 *
 * correct() signal is emitted when user selects correct option.
 * wrong() signal is emitted when user selects incorrect option.
 * done() signalled when user clicks the 'done' button at the end
 * of the use case.
 *
 * This class can be customised through polymorphism. The
 * virtual method createButton() allows child classes to
 * use any QAbstractButton for the options and the virtual
 * method createOptionsLayout() allows any QLayout to be
 * used to contain the option button area.
 *
 * Additional virtual methods exist for customising the
 * styling of the buttons when the correct answer is revealed or
 * the user is marked as correct.
 *
 * @see QuizIconWidget
 * @see QuizDemoWidget
 * @author Ronen
 */
class QuizWidget : public QWidget {
	Q_OBJECT
        // CONSTRUCTORS ///////////////////////////
public:
	QuizWidget(QWidget *parent = 0);
	~QuizWidget();

        /**
         * Configure the widget to display the given question.
         * The phrases are displayed in random order
         * @param p The possible answers from which the user can select.
         * @param a The actual answer.
         */
        void setQuestion(QList<Phrase> p, Phrase a);

        void reset();
        // PRIVATE METHODS ////////////////////////
private:
	// create the quiz buttons, add them to the 'options' list
	void createButtons();
	// add buttons to layout
	void createLayout();
	// disable buttons
	void disableButtons();
        // POLYMORPHISM ///////////////////////////
protected:
        /**
         * Handle the delay between user answering and revealing
         * the correct option.
         */
	virtual void timerEvent(QTimerEvent *event);
        /**
         * Paint the tick, cross and question mark icons.
         */
	virtual void paintEvent(QPaintEvent *event);
        /**
         * Give sensible size hint.
         */
        virtual QSize sizeHint() const;
        /**
         * Create a single button to display a phrase.
         * Default implementation creates a QPushButton showing
         * the phrase text.
         * Override for custom buttons
         * @param Phrase phrase The phrase this button should represent.
         * @param int index The number of this button, 0 being the
         * top button.
         * @return QAbstractButton* Some sort of button which must inherit
         * from the QAbtractButton interface.
         */
        virtual QAbstractButton* createButton(Phrase phrase, int index);
        /**
         * Create the central layout which contains the option buttons.
         * Override for custom layouts. Default layout is a QVBoxLayout
         * @param options buttons given as parameter
         * layout returned
         */
	virtual QLayout* createOptionsLayout(const QList<QAbstractButton*> options);

	// style the button for a correct answer
	virtual void correctAnswer(QAbstractButton* button);
	// style the button for a wrong answer
	virtual void wrongAnswer(QAbstractButton* button);
	// style the button to reveal the actual correct answer
	virtual void revealAnswer(QAbstractButton* button);

        /**
         * Notify derived class when the user has selected an option,
         * be it right or wrong.
         */
        virtual void answerSelected() {return;}
        // SIGNALS ////////////////////////////////////////
signals:
        /**
         * User has selected the correct answer.
         */
	void correct();
        /**
         * User has selected the wrong answer;
         */
	void wrong();
        /**
         * User has reviewed his result and dismissed the quiz.
         */
        void done();
        // POLYMORPHIC SLOTS ///////////////////////////
public slots:
        /**
         * Allows derived classes to clean up when 'done' button is pressed.
         */
        virtual void cleanup() {return;}
        // PRIVATE SLOTS ///////////////////////////////
private slots:
        /**
         * The user has selected an option.
         * This method determines the signal source using sender()
         * and starts the single shot timer which will cause
         * the answer to be marked in timerEvent().
         */
	void optionClicked();
        // INHERITED MEMBER VARIABLES //////////////////
protected:
        /**
         * The phrases constituting the question that this
         * quiz is testing. They are presented to the user
         * as options. One of them is the correct answer.
         */
        QList<Phrase> phrases;

        /**
         * Map of phrases to buttons, so we can
         * find the 'correct answer' button based on the correct Phrase.
         * Contains the master button pointers, although NOT in the
         * order may appear in the quiz. Use the createButton() index
         * parameter for that.
         */
        QMap<Phrase, QAbstractButton*> phraseToButtonMap;

        /**
         * The Phrase which is the correct answer. It is
         * a member of 'phrases'.
         */
        Phrase answer;

        /**
         * The answer which the user has selected.
         * NULL if the user has not yet selected an answer.
         */
        QAbstractButton* selected;

        /**
         * Whether the user has selected the correct answer.
         * We can tell whether an answer has been selected
         * at all by checking if selected == 0
         */
        bool selectedCorrect;
        /**
         * sequential buttons, in order of gui
         */
        QList<QAbstractButton*> buttonList;
        // PRIVATE MEMBERS ///////////////////////////////
private:
        QString answerText; // hack because timerEvent() doesn't like deferencing Phrase pointers (workaround)
	// timer id
	int timerId;
	// the tick image. loaded in constructor. painted in paintEvent()
	QImage tickImage;
	QImage questionImage;
	QImage crossImage;
        QPushButton *doneButton;

};

#endif

